<?php

namespace App\Kuafu\Order\Model;

use App\Kuafu\Base\Model\Traits\KfSoftDeletes;

use App\Kuafu\Base\Model\Traits\KfSplitRelation;
use App\Kuafu\Base\Model\Traits\KfUid;
use App\Kuafu\Common\Service\SeparateService;
use App\Kuafu\Coupon\Enum\CouponCodeEnum;
use App\Kuafu\Coupon\Enum\CouponEnum;
use App\Kuafu\CouponExt\Enum\CouponExtEnum;
use App\Kuafu\CouponExt\Model\OrderCouponExtSplitModel;
use App\Kuafu\Customer\Model\CustomerModel;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Model\Clickhouse\OrderCHModel;
use App\Kuafu\Order\Model\Clickhouse\OrderPayUnionCHModel;
use App\Kuafu\Order\Service\OrderCalcService;
use App\Kuafu\Order\Service\OrderDb;
use App\Kuafu\Order\Service\OrderService;
use App\Kuafu\Order\Service\OrderTable;
use App\Kuafu\Base\Model\BaseModel;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Model\RefundStreamModel;
use App\Kuafu\Shop\Model\Shop;
use App\Kuafu\User\Exceptions\UserException;
use App\Kuafu\WaiMai\Enum\WaiMaiDBEnum;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Facades\DB;

class OrderSplitModel extends BaseModel
{
    use KfSoftDeletes, KfUid, KfSplitRelation;

    public $incrementing = false;

//    public static $snakeAttributes = false;

//    protected $connection = 'mysqlOrder_2';
    protected $primaryKey = 'orderId';

    protected $fillable = [
        'orderId',
        'brandId',
        'shopId',
        'userId',
        'platformId',
        'sourceType',
        'serialNum',
        'offOrderId',
        'originalPrice',
        'orderShouldPrice',
        'shouldPrice',
        'discountPrice',
        'couponPrice',
        'couponCostPrice',
        'realDiscountPrice',
        'realPayPrice',
        'payPrice',
        'payStatus',
        'refundMoney',
        'payAction',
        'payChannel',
        'completeTime',
        'orderStatus',
        'refundStatus',
        'isSelfDelivery',
        'deliveryType',
        'distributionId',
        'distributionPer',
        'distributionAmount',
        'remark',
        'isDeleted',
        'createdBy',
        'createdByUid',
        'updatedBy',
        'updatedByUid',
        'createdAt',
        'updatedAt',
        'invoiceStatus',
        'thirdOrderId',
        'thirdOrderSource'
    ];
    protected $hidden   = [];

    private static $startAt, $endAt;

    public static string $tableName;
    public static string $connectionName;
    public static string $shopId;

    public static function suffix($shopId)
    {
        if (is_int($shopId) && $shopId < 0) {
            $shopId = 0;
        }

        self::$connectionName = OrderDb::orderDbConnection($shopId);
        self::$tableName      = OrderTable::orderTableName($shopId);
        self::$shopId         = $shopId;
        return new static;
    }

    public function getTable()
    {
        return self::$tableName ?? parent::getTable();
    }

    public function getConnectionName()
    {
        return self::$connectionName ?? parent::getConnectionName();
    }
//
//    public function setConnection($name)
//    {
//        return parent::setConnection($name); // TODO: Change the autogenerated stub
//    }

    /**
     * 插入主表数据
     *
     * @param $data
     */
    public static function insertOrder($data)
    {
        self::query()->insert($data);
    }

    /**
     * 插入主表数据 [格式化之后的]
     *
     * @param array $data
     * @throws UserException
     */
    public static function insertOrderAfterFormat(array $data)
    {
        $afterData = self::formatInsertData($data);
        self::query()->insert($afterData);
    }

    /**
     * 更新 主表数据
     *
     * @param $data
     */
    public static function updateOrder($data)
    {
        self::query()->where('orderId', (int)$data['orderId'])->update($data);
    }

    public static function setData(int $id, array $data): int
    {
        $query = self::query()->where('id', $id)->first();
        if (!$query) {
            return 0;
        }

        foreach ($data as $k => $v) {
            $query->$k = $v;
        }

        return $query->save();
    }

    /**
     * 查询指定品牌店铺的订单列表
     * @param $completeTimeStart
     * @param $completeTimeEnd
     * @param $serialNum
     * @param $pageSize
     * @param $pageNum
     * @param $field
     * @param $orderColumn
     * @param $orderType
     * @param $brandId
     * @param $shopId
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public static function getDataPage(
        $completeTimeStart,
        $completeTimeEnd,
        $serialNum,
        $pageSize,
        $pageNum,
        $field,
        $orderColumn,
        $orderType,
        $brandId,
        $shopId,
        $orderStatus,
        bool $withOrderDetail = false
    ) {
        $time = false;
        if (!empty($completeTimeStart) && !empty($completeTimeEnd)) {
            $time = true;
        }
        return self::query()
                   ->when($time, function ($query) use ($completeTimeStart, $completeTimeEnd) {
                       $query->whereBetween('createdAt', [$completeTimeStart, $completeTimeEnd]);
                   })
                   ->when($serialNum, function ($query) use ($serialNum) {
                       $query->where('serialNum', '=', "$serialNum");
                   })
                   ->when($orderStatus >= 0, function ($query) use ($orderStatus) {
                       $query->where('orderStatus', '=', "$orderStatus");
                   })
                   ->where(['brandId' => $brandId, 'shopId' => $shopId])
                   ->when($orderColumn, function ($query) use ($orderColumn, $orderType) {
                       if ($orderColumn == 'createdAt') {
                           $query->orderBy($orderColumn, $orderType);
                       } else {
                           $query->orderBy($orderColumn, $orderType);
                           $query->orderBy('createdAt', 'DESC');
                       }
                   })
                   ->when($withOrderDetail, function ($query) {
                       $query->with('orderDetailRel');
                   })
                   ->paginate($pageSize, $field, 'page', $pageNum);
    }


    public static function getOrderPriceCount(
        $completeTimeStart,
        $completeTimeEnd,
        $shopId,
        $brandId,
        $orderStatus,
        $serialNum
    ) {
        return self::query()
                   ->where(['shopId' => $shopId, 'brandId' => $brandId])
                   ->when($orderStatus >= 0, function ($query) use ($orderStatus) {
                       $query->where('orderStatus', '=', "$orderStatus");
                   })
                   ->when($serialNum, function ($query) use ($serialNum) {
                       $query->where('serialNum', '=', "$serialNum");
                   })
                   ->whereBetween('createdAt', [$completeTimeStart, $completeTimeEnd])
                   ->select([
                       'originalPrice',
                       'shouldPrice',
                       'discountPrice',
                       'payPrice',
                       'realPayPrice',
                       'realDiscountPrice'
                   ])
                   ->get();
    }

    public static function getOrderFieldByOrderId($orderId, $field)
    {
        return self::query()
                   ->where(['orderId' => $orderId])
                   ->select($field)
                   ->first();
    }


    public static function getUserOrderList(
        $userId,
        $pageSize,
        $pageNum,
        $flagComplain = CodeEnum::ORDER_STATUS_DEFAULT
    ) {
        $field = [
            'orderId',
            'shopId',
            'createdAt',
            'payPrice',
            'orderStatus',
            'shouldPrice',
            'payStatus',
            'orderShouldPrice'
        ];
        return self::query()
                   ->where(['userId' => $userId])
                   ->when(
                       $flagComplain == CodeEnum::ORDER_STATUS_APPLET, function ($query) {//1-小程序投诉（获取支付完成的订单，最近10条）
                       $query->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED);
                   }
                   )
                   ->orderBy('createdAt', 'DESC')
                   ->paginate($pageSize, $field, 'page', $pageNum);
    }

    public static function getUserOrderFieldByOrderId($userId, $orderId, $field)
    {
        return self::query()
                   ->where(['orderId' => $orderId, 'userId' => $userId])
                   ->select($field)
                   ->first();
    }

    public function scopeFilterTime($query)
    {
        return $query->whereBetween('createdAt', [self::$startAt, self::$endAt]);
    }

    public static function setStatus(int $id, int $status): int
    {
        return self::query()->where('id', $id)->update(['status' => $status]);
    }

    public static function setStartEndAt($startAt, $endAt)
    {
        self::$startAt = $startAt;
        self::$endAt   = $endAt;
    }

    public function shopRel()
    {
        return $this->hasOne(Shop::class, 'id', 'shopId');
    }

    public function customerRel()
    {
        return $this->hasOne(CustomerModel::class, 'id', 'userId');
    }

    public function orderOperateRecordRel()
    {
        return $this->hasMany(OrderOperateRecordModel::class, 'orderId', 'orderId');
    }

    public function orderDetailRel(): HasMany
    {
        $table   = OrderTable::orderDetailTableName(self::$shopId);
        $connect = OrderDb::orderDbConnection(self::$shopId);
        return $this->hasManyWithTable(OrderDetailSplitModel::class, 'orderId', 'orderId', $table, $connect);
    }


    public function orderCouponRel(): HasMany
    {
        $table   = OrderTable::orderCouponTableName(self::$shopId);
        $connect = OrderDb::orderDbConnection(self::$shopId);

        return $this->hasManyWithTable(OrderCouponSplitModel::class, 'orderId', 'orderId', $table, $connect);
    }

    public function orderUserInfoRel(): HasOne
    {
        $table   = OrderTable::orderUserInfoTableName(self::$shopId);
        $connect = OrderDb::orderDbConnection(self::$shopId);

        return $this->hasOneWithTable(OrderUserInfoSplitModel::class, 'orderId', 'orderId', $table, $connect);
    }

    public function orderCouponExtRel(): HasMany
    {
        $table   = OrderTable::orderCouponExtTableName(self::$shopId);
        $connect = OrderDb::orderDbConnection(self::$shopId);

        return $this->hasManyWithTable(OrderCouponExtSplitModel::class, 'orderId', 'orderId', $table, $connect);
    }

    public function orderExtRel(): HasMany
    {
        $table   = OrderTable::orderExternalTableName(self::$shopId);
        $connect = OrderDb::orderDbConnection(self::$shopId);

        return $this->hasManyWithTable(OrderExternalSplitModel::class, 'orderId', 'orderId', $table, $connect);
    }

    public function orderExtOneRel(): HasOne
    {
        $table   = OrderTable::orderExternalTableName(self::$shopId);
        $connect = OrderDb::orderDbConnection(self::$shopId);

        return $this->hasOneWithTable(OrderExternalSplitModel::class, 'orderId', 'orderId', $table, $connect);
    }

    public function orderDiscountRel(): HasMany
    {
        $table   = OrderTable::orderDiscountTableName(self::$shopId);
        $connect = OrderDb::orderDbConnection(self::$shopId);

        return $this->hasManyWithTable(OrderDiscountSplitModel::class, 'orderId', 'orderId', $table, $connect);
    }

    public function orderPayStreamRel(): HasMany
    {
        $tableName = (new PayStreamModel)->getBaseTable();
        $connect   = OrderDb::orderDbConnection(self::$shopId);

        return $this->hasManyWithTable(PayStreamModel::class, 'orderId', 'orderId', $tableName, $connect);
    }

    public function orderRefundStreamRel(): HasMany
    {
        return $this->hasMany(RefundStreamModel::class, 'orderId', 'orderId');
    }

    public static function getOrderDetailByOrderId(
        $orderId,
        $orderFiled,
        $detailField,
        $couponField,
        $discountField,
        $orderCouponField
    ) {
        // 为payStreamRel服务
        (new BaseModel())->setSplitShopId(self::$shopId);

        return self::query()
                   ->with([
                       'orderDetailRel' => function ($query) use ($detailField) {
                           $query->select($detailField)->orderBy("id", "asc");
                       }
                   ])
                   ->with([
                       'orderCouponExtRel' => function ($query) use ($couponField) {
                           $query->where('couponExtStatus', CouponExtEnum::COUPON_STATUS_USED);
                           $query->select($couponField);
                       }
                   ])
                   ->with([
                       'orderDiscountRel' => function ($query) use ($discountField) {
                           $query->where('discountType', '!=', CodeEnum::ORDER_DISCOUNT_TYPE_CUSTOM_PAY);
                           $query->select($discountField);
                       }
                   ])
                   ->with([
                       'orderCouponRel' => function ($query) use ($orderCouponField) {
                           $query->whereIn('status',
                               [OrderCouponSplitModel::STATUS_USED, OrderCouponSplitModel::STATUS_WAIT])
                                 ->with('customerCouponRel', function ($cQuery) {
                                     $cQuery->select(['id', 'couponCode', 'cappedAmount', 'canUseProduct']);
                                 })
                                 ->select($orderCouponField);
                       }
                   ])
                   ->with([
                       'orderExtOneRel' => function ($query) {
                           $query->select(['orderId', 'extOrderId', 'payPrice']);
                       }
                   ])
                   ->with(['orderPayStreamRel', 'orderPayStreamRel.streamCustomPaymentRel'])
                   ->with(['orderRefundStreamRel', 'orderRefundStreamRel.streamCustomPaymentRel'])
                   ->select($orderFiled)
                   ->where('orderId', '=', (int)$orderId)
                   ->first();
    }

    public static function productSellStatistics($shopId, $startAt, $endAt)
    {
        return self::query()
                   ->with([
                       'orderDetailRel' => function ($query) {
                           $query->select(['id', 'orderId', 'productId', 'productName', 'num', 'categoryId']);
                       }
                   ])
                   ->select(['orderId'])
                   ->where('shopId', '=', $shopId)
                   ->whereBetween('createdAt', [$startAt, $endAt])
                   ->get();
    }

    public static function getUserOrderDetailByOrderId($userId, $orderId, $orderFiled, $detailField, $couponField)
    {
        return self::query()
                   ->with([
                       'orderDetailRel' => function ($query) use ($detailField) {
                           $query->select($detailField);
                       },
                       'orderCouponRel' => function ($query) use ($couponField) {
                           $query->select($couponField);
                       },
//                       'orderUserInfoRel'
                   ])
                   ->with(['orderExtRel'])
                   ->select($orderFiled)
                   ->where(['orderId' => (int)$orderId])
                   ->when($userId > 0, function ($query) use ($userId) {
                       $query->where('userId', '=', "$userId");
                   })
                   ->first();
    }


    //传入开始结束时间获取实际收入总数
    public static function getTotalIncomeByTime(array $time)
    {
        return self::query()
                   ->where('orderStatus', '=', CodeEnum::ORDER_STATUS_FINISHED)
                   ->whereBetween('createdAt', $time)
                   ->sum('payPrice');
    }

    public function getSourceTypeTextAttribute(): string
    {
        return CodeEnum::SOURCE_TYPES[$this->sourceType] ?? '';
    }

    public function getOrderStatusTextAttribute(): string
    {
        return CodeEnum::STATUS_CODE_TEXT[$this->orderStatus] ?? '';
    }


    public function getRefundStatusTextAttribute(): string
    {
        return CodeEnum::REFUND_CODE_TEXT[$this->refundStatus] ?? '';
    }

    public function getPayChannelTextAttribute(): string
    {
        return CodeEnum::CHANNEL_CODE_TEXT[$this->payChannel] ?? '';
    }

    public static function getOrderDiscountList(
        $shopId,
        $payChannel,
        $sourceType,
        $completeTimeStart,
        $completeTimeEnd,
        bool $returnLists = true
    ) {
        $engine = (new SeparateService(strtotime($completeTimeStart), strtotime($completeTimeEnd)))->check();
        if ($engine == SeparateService::DB) {
            $model = self::suffix($shopId);
        } else {
            $model = OrderCHModel::query();
        }

        $lists = $model
                     ->with([
                         'orderDetailRel' => function ($query) {
                             $query->where('type', 0)->where('isDeleted', 0)->where('refundNum', 0);
                         }
                     ])
                     ->with([
                         'orderCouponExtRel' => function ($query) {
                             $query->where('couponExtStatus', CouponExtEnum::COUPON_STATUS_USED);
                         }
                     ])
                     ->with([
                         'orderDiscountRel' => function ($query) {
                             $query->where('discountType', '!=', CodeEnum::ORDER_DISCOUNT_TYPE_CUSTOM_PAY);
                         }
                     ])
                     ->with([
                         'orderCouponRel' => function ($query) {
                             $query->where('status', 1)->where('isDeleted', 0);
                         }
                     ])
                     ->with([
                         'orderExtOneRel' => function ($query) {
                             $query->select(['orderId', 'extOrderId', 'payPrice']);
                         }
                     ])
                     ->where('shopId', '=', $shopId)
                     ->when($payChannel, function ($query) use ($payChannel) {
                         $query->where('payChannel', $payChannel);
                     })
                     ->when(is_array($sourceType) && count($sourceType),
                         function ($query) use ($sourceType) {
                             $query->whereIn('sourceType', $sourceType);
                         })
                     ->where('orderStatus', CodeEnum::ORDER_STATUS_FINISHED)
                     ->whereBetween('completeTime', [strtotime($completeTimeStart), strtotime($completeTimeEnd)]);

        if ($returnLists) {
            return $lists->get();
        }

        return $lists->count();
    }

    /**
     * 整理 Order 入库/更新 数据
     * @throws UserException
     */
    public static function formatInsertData($data): array
    {
        $insertData = [
            'orderId'           => $data['orderId'],
            'offOrderId'        => $data['offOrderId'],
            'brandId'           => $data['brandId'],
            'shopId'            => $data['shopId'],
            'userId'            => $data['userId'],
            'sourceType'        => $data['sourceType'],
            'serialNum'         => $data['serialNum'],
            'orderShouldPrice'  => $data['orderShouldPrice'],
            'originalPrice'     => $data['originalPrice'],
            'shouldPrice'       => $data['shouldPrice'],
            'discountPrice'     => $data['discountPrice'],
            'couponPrice'       => $data['couponPrice'],
            'completeTime'      => $data['completeTime'],
            'couponCostPrice'   => $data['couponCostPrice'],
            'realDiscountPrice' => $data['realDiscountPrice'],
            'remark'            => $data['remark'],
            'createdAt'         => $data['createdAt'],
            'createdByUid'      => $data['createdByUid'],
            'createdBy'         => $data['createdBy'],
            'updatedAt'         => $data['updatedAt'],
            'updatedByUid'      => $data['updatedByUid'],
            'updatedBy'         => $data['updatedBy'],
            'payPrice'          => $data['payPrice'],
            'realPayPrice'      => $data['realPayPrice'],
            'orderStatus'       => $data['orderStatus'],
            'refundStatus'      => $data['refundStatus'],
            'payChannel'        => $data['payChannel'],
            'payStatus'         => $data['payStatus'],
            'isOffline'         => $data['isOffline'] ?? 0
        ];

        return $insertData;
    }

    /**
     * 更新 发票状态
     *
     * @param $orderId
     * @param $invoiceStatus
     * @return int
     */
    public static function invoiceStatusUpdate($orderId, $invoiceStatus)
    {
        return self::query()->where('orderId', $orderId)->update(['invoiceStatus' => $invoiceStatus]);
    }

    /**
     * 减少开票次数
     *
     * @param $orderId
     * @return int
     */
    public static function reduceInvoiceCancelCount($orderId)
    {
        return self::query()->where('orderId', $orderId)
                   ->update(['invoiceCanCancelCount' => DB::raw('invoiceCanCancelCount-1')]);
    }
}
